class IUP_GET_PARAM
-- Shows a modal dialog for capturing parameter values using several types of 
-- controls. After create the dialog with "get_param" you can add any 
-- amout of parameters with features "add_xxxx_parameter". The first 
-- argument in these features are the label of the parameter, you can 
-- add any number of characters %T at the label to indent the parameter entry.
-- The argument "tip" is a string that is displayed as a tool-tip for the main 
-- control of the parameter. To add break lines in tool-tip string 
-- add the characters "%%r". You can pass an empty string if don't want a 
-- tool-tip. You can also add "separators" to organize the parameters.
-- The dialog is resizable if it contains a string, a multiline string or a 
-- number with a valuator. All the multiline strings will increase size equally 
-- in both directions.
--
-- The dialog is resizable if it contains a string, a multiline string or a 
-- number with a valuator. All the multiline strings will increase size equally 
-- in both directions.
--
-- The dialog uses a global attribute called "PARENTDIALOG" as the parent 
-- dialog if it is defined. It also uses a global attribute called "ICON" as 
-- the dialog icon if it is defined.

inherit
	IUP_WIDGET
		redefine
			execute_param
		end

create {ANY}
	get_param

feature {ANY}

	get_param (title: STRING;
              act: FUNCTION[TUPLE[IUP_GET_PARAM, INTEGER, POINTER], INTEGER];
              user_data: POINTER)
		-- Create the dialog.
		--
		-- title: dialog title.
		-- act: user callback to be called whenever a parameter value was 
		-- changed, and when the user pressed the OK button.
		-- user_data: user pointer passed to the user callback.
		--
		-- The callback receive three arguments:
		--
		-- dialog: the IUP_GET_PARAM object
		-- param_index: current parameter being changed. Can have negative values 
		-- to indicate specific situations:
		--    -1 = if the user pressed the button 1.
		--    -2 = after the dialog is mapped and just before it is shown.
		--    -3 = if the user pressed the button 2.
		--    -4 = if the user pressed the button 3, if any.
		--    -5 = if the user clicked on the dialog close button.
		-- user_data: a user pointer that is passed in the function call.
		--
		-- Returns: You can reject the change or the button action by returning 0 
		-- in the callback, otherwise you must return 1. By default button 1 and 
		-- button 2 will close the dialog.
		--
		-- You should not programmatically change the current parameter value 
		-- during the callback. On the other hand you can freely change the value 
		-- of other parameters.
		do
			t := title
			cb_param := act
			ud := user_data
			pe := 0

		   create f.make_empty
			create pd.default_create
		end

	launch: INTEGER
		-- Show the dialog, return 1 if the button 1 was pressed, 0 if the button 
		-- 2 was pressed or if an error occurred.
		do
			iup_open.set_get_param (Current)

			Result := int_get_param (t.to_external, ud,
			                         f.to_external, pd.count, pe,
											 pd.to_external)
		end

	-- Set parameters

	add_boolean_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- Add an entry for a boolean parameter, it shows a True/False toggle.
		--	The "extra_data" parameter are optional strings, in the form 
		--	"false_title,true_title" for boolean types to be displayed after the 
		--	toggle. The strings can not have commas ',', nor brackets '[' or ']'.
		-- The "def" parameter should be a pointer to a integer with 
		-- the initial value (0 for False and 1 to True).
		do
			f.append_string(label)
			f.append_string("%%b")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_integer_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to a C integer value. The "extra_data" parameter is a 
		-- string of the form "min,max,step". The "max" and "step" values can be 
		-- omitted.	When "min" and "max" are specified a valuator will also be 
		-- added to change the value. To specify "step", "max" must be also 
		-- specified. "step" is the size of the increment. The "def" parameter 
		-- should be a pointer to a INTEGER with the initial value.
		-- A integer parameter always has a spin attached to the text to 
		-- increment and decrement the value.
		do
			f.append_string(label)
			f.append_string("%%i")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_real_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to a C real value. The "extra_data" parameter is a 
		-- string of the form "min,max,step". The "max" and "step" values can be 
		-- omitted.	When "min" and "max" are specified a valuator will also be 
		-- added to change the value. To specify "step", "max" must be also 
		-- specified. "step" is the size of the increment. The "def" parameter 
		-- should be a pointer to a REAL_32 with the initial value.
		-- A real parameter only has a spin in a full interval is defined (min 
		-- and max), in this case the default step is (max-min)/20.
		do
			f.append_string(label)
			f.append_string("%%r")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_double_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to a C double value. The "extra_data" parameter is a 
		-- string of the form "min,max,step". The "max" and "step" values can be 
		-- omitted.	When "min" and "max" are specified a valuator will also be 
		-- added to change the value. To specify "step", "max" must be also 
		-- specified. "step" is the size of the increment. The "def" parameter 
		-- should be a pointer to a REAL_64 with the initial value.
		-- A double parameter only has a spin in a full interval is defined (min 
		-- and max), in this case the default step is (max-min)/20.
		do
			f.append_string(label)
			f.append_string("%%R")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_angle_real_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to a C real value. The "extra_data" parameter is a 
		-- string of the form "min,max,step". The "max" and "step" values can be 
		-- omitted.	When "min" and "max" are specified a dial will also be 
		-- added to change the value (only if "load_iup_controls" is 
		-- called on IUP). To specify "step", "max" must be also 
		-- specified. "step" is the size of the increment. The "def" parameter 
		-- should be a pointer to a REAL_32 with the initial value.
		do
			f.append_string(label)
			f.append_string("%%a")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_angle_double_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to an C double value. The "extra_data" parameter is a 
		-- string of the form "min,max,step". The "max" and "step" values can be 
		-- omitted.	When "min" and "max" are specified a dial will also be 
		-- added to change the value (only if "load_iup_controls" is 
		-- called on IUP). To specify "step", "max" must be also 
		-- specified. "step" is the size of the increment. The "def" parameter 
		-- should be a pointer to a REAL_64 with the initial value.
		do
			f.append_string(label)
			f.append_string("%%A")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_string_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to a string value. The "extra_data" parameter is an optional 
		-- mask for the string. The maks have the same format used in IUP_TEXT.
		-- For more information see:
		-- http://webserver2.tecgraf.puc-rio.br/iup/en/attrib/iup_mask.html
		-- Pass an empty string if don't want a mask.
		--	The "def" parameter should be a pointer to a STRING with the initial 
		-- value (if any) and with enough space for the user entry.	
		do
			f.append_string(label)
			f.append_string("%%s")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_multiline_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A field to a multiline string value. The "extra_data" parameter is an 
		-- optional mask for the string. The maks have the same format used in 
		-- IUP_TEXT. For more information see:
		-- http://webserver2.tecgraf.puc-rio.br/iup/en/attrib/iup_mask.html
		-- Pass an empty string if don't want a mask.
		-- The "def" parameter should be a pointer to a STRING with the initial 
		-- value (if any) and with enough space for the user entry.	
		do
			f.append_string(label)
			f.append_string("%%m")

			if not extra_data.is_empty then
				f.append_string("[")
				f.append_string(extra_data)
				f.append_string("]")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_list_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A dropdown list box. The "extra_data" parameter is a string of the 
		-- form "item0|item1|item2|...|itemN" with the titles of the items in the 
		-- list. At least one item must exist. Items index are zero based start. 
		-- The "def" parameter should be a pointer to an INTEGER with 
		-- the initial value (the selected item).
		do
			f.append_string(label)
			f.append_string("%%l")

			if not extra_data.is_empty then
				f.append_string("|")
				f.append_string(extra_data)
				f.append_string("|")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_radio_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A list of toggles inside a radio. The "extra_data" parameter is a 
		-- string of the form "item0|item1|item2|...|itemN" with 
		-- the titles of the items in the list. At least one item must exist. 
		-- Items index are zero based start. The "def" parameter should be a 
		-- pointer to an INTEGER with the initial value (the selected item).
		do
			f.append_string(label)
			f.append_string("%%o")

			if not extra_data.is_empty then
				f.append_string("|")
				f.append_string(extra_data)
				f.append_string("|")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_separator (label: STRING)
		-- Separator. Shows a horizontal line separator label, in this case text 
		-- can be an empty string.
		do
			f.append_string(label)
			f.append_string("%%t")
			f.append_string("%N")

			pe := pe + 1
		end

	add_date_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A string parameter, but the interface uses a IUP_DATE_PICK element to 
		-- select a date. The "extra_data" parameter are simply IUP_DATE_PICK 
		-- attributes in a single string. The "def" parameter should be a pointer 
		-- to a string with the initial value and with enough space for the user 
		-- entry.	
		do
			f.append_string(label)
			f.append_string("%%d")

			if not extra_data.is_empty then
				f.append_string("|")
				f.append_string(extra_data)
				f.append_string("|")
			end

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_file_parameter (label, extra_data, tip: STRING; def: POINTER)
		-- A string parameter with a button to open a file selection dialog box. 
		-- The "estra_data" is a string of the form 
		-- "dialogtype|filter|directory|nochangedir|nooverwriteprompt"
		-- with the respective attribute values passed to the IUP_FILE_DIALOG 
		-- control when activated. All '|' must exist, but you can let empty 
		-- values to use the default values.
		-- The "def" parameter should be a pointer to a string with the 
		-- initial value and with enough space for the user entry.
		do
			f.append_string(label)
			f.append_string("%%f")

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_color_parameter (label, tip: STRING; def: POINTER)
		-- A string parameter with a color button to open a color selection 
		-- dialog box. The "def" parameter should be a pointer to a string 
		-- with the initial value and with enough space for the user entry.
		do
			f.append_string(label)
			f.append_string("%%c")

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_font_parameter (label, tip: STRING; def: POINTER)
		-- A string parameter with a font button to open a font selection 
		-- dialog box. The "def" parameter should be a pointer to a string 
		-- with the initial value and with enough space for the user entry.
		do
			f.append_string(label)
			f.append_string("%%n")

			if not tip.is_empty then
				f.append_string("{")
				f.append_string(tip)
				f.append_string("}")
			end

			f.append_string("%N")
			pd.add_last(def)
		end

	add_widget_parameter (label: STRING; wgt: IUP_WIDGET)
		-- Add a widget that will be managed by the application, it will be 
		-- placed after the parameters and before the buttons
		do
			f.append_string(label)
			f.append_string("%%h")
			f.append_string("%N")
			pd.add_last(wgt.widget)
		end

	add_buttons_parameter (titles: STRING)
		-- Buttons titles. Allow to redefine the default button titles (OK and 
		-- Cancel), and to add a third button. Use "button1,button2,button3". 
		-- Can omit one of them, it will use the default name.
		do
			f.append_string("Bt %%u")
			f.append_string("[")
			f.append_string(titles)
			f.append_string("]")
			f.append_string("%N")

			pe := pe + 1
		end

	-- Attributes

	set_precision (decimals: INTEGER)
		-- The default number of decimal places used in floating point output by 
		-- some controls.
		--
		-- The default precision for real value display is given by the global 
		-- attribute DEFAULTPRECISION. But inside the callback the application 
		-- can use this feature to use another value. It will work only during 
		-- interactive changes. The decimal symbol will used the 
		-- DEFAULTDECIMALSYMBOL global attribute. Local attributes may overwrite 
		-- the default. Default: 2.
		require
			decimals >= 0
		do
			iup_open.set_attribute (Current, "PRECISION", decimals.to_string)
		end

	get_button (number: INTEGER): IUP_BUTTON
		-- Returns the button 1, 2 or 3 (if any).
		require
			number >= 1
			number <= 3
		local
			p: POINTER
			b: IUP_BUTTON
		do
			if number.is_equal(1) then
				p := iup_open.get_attribute_ihandle(Current, "BUTTON1")
			elseif number.is_equal(2) then
				p := iup_open.get_attribute_ihandle(Current, "BUTTON2")
			elseif number.is_equal(3) then
				p := iup_open.get_attribute_ihandle(Current, "BUTTON3")
			end

			create b.button_widget(p)
			Result := b
		end

	--get_parameter_label_at (number: INTEGER): IUP_LABEL
	--	local
	--		str: STRING
	--		a_label: IUP_LABEL
	--		p1, p2: POINTER
	--	do
	--		str := "PARAM"
	--		str.append_string(number.to_string)
	--		p1 := iup_open.get_attribute_ihandle(Current, str)
	--		p2 := iup_open.get_attribute_ihandle_from_handle(p1, str)
	--		
	--		create a_label.label_widget(p2)
	--		Result := a_label
	--	end

	get_parameter_value_at (index: INTEGER): STRING
		-- Get the value, as string, that the user writes in the parameter at
		-- provided index.
		local
			str: STRING
			p: POINTER
		do
			str := "PARAM"
			str.append_string(index.to_string)
			p := iup_open.get_attribute_ihandle(Current, str)

			if p.is_not_null then
				Result := iup_open.get_attribute_from_handle(p, "VALUE")
			else
				Result := ""
			end
		end

	set_parameter_value_at (value: STRING; index: INTEGER)
		-- Set the value, passed as string, in the parameter at provided index.
		-- This set the value at the control and at the auxiliary 
		-- control (if any).
		local
			str: STRING
			p1, p2: POINTER
		do
			str := "PARAM"
			str.append_string(index.to_string)
			p1 := iup_open.get_attribute_ihandle(Current, str)

			if p1.is_not_null then
				iup_open.set_attribute_in_handle(p1, "VALUE", value)
			end

			p2 := iup_open.get_attribute_ihandle_from_handle(p1, "AUXCONTROL")

			if p2.is_not_null then
				iup_open.set_attribute_in_handle(p2, "VALUE", value)
			end
		end

	set_parameter_visible_columns_at (value, index: INTEGER)
		-- Set the visible columns in string parameters (those 
		-- added with "add_string_parameter").
		local
			str: STRING
			p: POINTER
		do
			str := "PARAM"
			str.append_string(index.to_string)
			p := iup_open.get_attribute_ihandle(Current, str)

			if p.is_not_null then
				iup_open.set_attribute_in_handle(p, "VISIBLECOLUMNS",
															value.to_string)
			end
		end

	get_spinning: INTEGER
		-- A integer parameter always has a spin attached to the text to 
		-- increment and decrement the value. A real parameter only has a spin in 
		-- a full interval is defined (min and max), in this case the default 
		-- step is (max-min)/20. When the callback is called because a spin was 
		-- activated then this feature return a non zero value.
		local
			str: STRING
		do
			str := iup_open.get_attribute (Current, "SPINNING")

			if str /= Void then
				if str.is_integer then
					Result := str.to_integer
				end
			end
		end

feature {IUP}

	execute_param (handle: POINTER; param_index: INTEGER; user_data: POINTER): INTEGER
		do
			widget := handle
			Result := cb_param.item([Current, param_index, user_data])
		end

feature {}

	cb_param: FUNCTION[TUPLE[IUP_GET_PARAM, INTEGER, POINTER], INTEGER]

	t, f: STRING
	ud: POINTER
	pe: INTEGER
	pd: ARRAY[POINTER]

	-- Internals

	int_get_param (title, user_data, format: POINTER; param_count, param_extra: INTEGER; param_data: POINTER): INTEGER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "get_param_dialog"
         }"
      end

end -- end class

-- The MIT License (MIT)

-- Copyright (c) 2016, 2017 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
